/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package managedbean.SalesForecast;

import merlion.mrp.ppm.pojo.LabelNValue;
import merlion.mrp.ppm.pojo.LongHolder;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import merlion.common.util.Consts;
import merlion.mrp.ppm.entity.SalesForecast;
import merlion.mrp.ppm.entity.UpdateIndiv;
import merlion.mrp.ppm.session.SalesForecastingSessionLocal;
import org.primefaces.context.RequestContext;

/**
 *
 * @author Zhang Ying
 */
@ManagedBean(name = "sfUpdateManagerBean")
@ViewScoped
public class SalesForecastUpdateManagerBean {

    public static final String NEW_UPDATE_INDIVS = "newUpdateIndivs";
    @EJB
    private SalesForecastingSessionLocal salesForecastSession;
    private ArrayList<String> labels;
    private SalesForecast selectedSF;
    // new updateIndiv
    private Timestamp currentTime;
    private ArrayList<UpdateIndiv> newUpdateIndivs;
    // for c:forEach
    private ArrayList<Integer> counter;
    private ArrayList<Integer> counterForProduct;
    // editable fields
    private ArrayList<ArrayList<LongHolder>> humanAdjusts;
    private ArrayList<ArrayList<LongHolder>> promotions;
    // dialog for mov average
    private Integer selectedProductId;
    private ArrayList<LabelNValue> referencedActual;

    /** Creates a new instance of SalesForecastUpdateManagerBean */
    public SalesForecastUpdateManagerBean() {
        // create new updateIndiv
        Calendar calendar = Calendar.getInstance();
        Date date = calendar.getTime();
        currentTime = new Timestamp(date.getTime());
        counter = new ArrayList<Integer>();
        for (int i = 0; i < 6; i++) {
            counter.add(new Integer(i));
        }
        counterForProduct = new ArrayList<Integer>();
        //newUpdateIndivs = new ArrayList<UpdateIndiv>();
        for (int i = 0; i < 4; i++) {
            //UpdateIndiv temp = new UpdateIndiv(currentTime);
            //newUpdateIndivs.add(temp);
            counterForProduct.add(new Integer(i));
        }
        selectedProductId = 0;
        referencedActual = new ArrayList<LabelNValue>();
//        humanAdjusts = new ArrayList<ArrayList<LongHolder>>();
//        promotions = new ArrayList<ArrayList<LongHolder>>();
    }

    // for general purpose
    private String getRedirectPath(String path) {
        return path + "?faces-redirect=true";
    }

    public String returnProductName(Integer pid) {
        if (pid.equals(0)) {
            return Consts.ProductType.BAR_A.getText();
        } else if (pid.equals(1)) {
            return Consts.ProductType.BAR_B.getText();
        } else if (pid.equals(2)) {
            return Consts.ProductType.BAR_C.getText();
        } else {
            return Consts.ProductType.BAR_D.getText();
        }
    }

    // all setters and getters
    public ArrayList<String> getLabels() {
        labels = new ArrayList<String>();
        if (getSelectedSF().getStartPeriodMonth() < 7) {
            labels.add(Consts.JAN);
            labels.add(Consts.FEB);
            labels.add(Consts.MAR);
            labels.add(Consts.APR);
            labels.add(Consts.MAY);
            labels.add(Consts.JUN);
        } else {
            labels.add(Consts.JUL);
            labels.add(Consts.AUG);
            labels.add(Consts.SEP);
            labels.add(Consts.OCT);
            labels.add(Consts.NOV);
            labels.add(Consts.DEC);
        }
        return labels;
    }

    public void setLabels(ArrayList<String> labels) {
        this.labels = labels;
    }

    public SalesForecast getSelectedSF() {
        if (selectedSF == null) {
            SalesForecast sf = (SalesForecast) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get(SalesForecastMgmtManagerBean.UPDATE_SF);
            if (sf != null) {
                selectedSF = sf;
            }
//            if (newUpdateIndivs == null) {
//                getNewUpdateIndivs();
//                // populate values
//                humanAdjusts = new ArrayList<ArrayList<LongHolder>>();
//                promotions = new ArrayList<ArrayList<LongHolder>>();
//                for (int i = 0; i < 4; i++) {
//                    ArrayList<LongHolder> temp1 = new ArrayList<LongHolder>();
//                    ArrayList<LongHolder> temp2 = new ArrayList<LongHolder>();
//                    for (int j = 0; j < 6; j++) {
//                        LongHolder lh1 = new LongHolder();
//                        LongHolder lh2 = new LongHolder();
//                        lh1.setL(newUpdateIndivs.get(i).getHumanAdjustList().get(j).getLongValue());
//                        lh2.setL(newUpdateIndivs.get(i).getPromotionList().get(j).getLongValue());
//                        temp1.add(lh1);
//                        temp2.add(lh2);
//                    }
//                    humanAdjusts.add(temp1);
//                    promotions.add(temp2);
//                }
//            }
        }
        return selectedSF;
    }

    public void setSelectedSF(SalesForecast selectedSF) {
        this.selectedSF = selectedSF;
    }

    public ArrayList<UpdateIndiv> getNewUpdateIndivs() {
        ArrayList<UpdateIndiv> uis = (ArrayList<UpdateIndiv>) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get(NEW_UPDATE_INDIVS);
        if (uis != null) {
            newUpdateIndivs = uis;
        }
        return newUpdateIndivs;
    }

    public void setNewUpdateIndivs(ArrayList<UpdateIndiv> newUpdateIndivs) {
        this.newUpdateIndivs = newUpdateIndivs;
    }

    public ArrayList<Integer> getCounter() {
        return counter;
    }

    public void setCounter(ArrayList<Integer> counter) {
        this.counter = counter;
    }

    public ArrayList<Integer> getCounterForProduct() {
        return counterForProduct;
    }

    public void setCounterForProduct(ArrayList<Integer> counterForProduct) {
        this.counterForProduct = counterForProduct;
    }

    public ArrayList<ArrayList<LongHolder>> getHumanAdjusts() {
        if (humanAdjusts == null || humanAdjusts.isEmpty()) {
            humanAdjusts = new ArrayList<ArrayList<LongHolder>>();
            for (int i = 0; i < 4; i++) {
                ArrayList<LongHolder> temp1 = new ArrayList<LongHolder>();
                for (int j = 0; j < 6; j++) {
                    LongHolder lh1 = new LongHolder();
                    lh1.setL(getNewUpdateIndivs().get(i).getHumanAdjustList().get(j).getLongValue());
                    temp1.add(lh1);
                }
                humanAdjusts.add(temp1);
            }
        }
        return humanAdjusts;
    }

    public void setHumanAdjusts(ArrayList<ArrayList<LongHolder>> humanAdjusts) {
        this.humanAdjusts = humanAdjusts;
    }

    public ArrayList<ArrayList<LongHolder>> getPromotions() {
        if (promotions == null || promotions.isEmpty()) {
            promotions = new ArrayList<ArrayList<LongHolder>>();
            for (int i = 0; i < 4; i++) {
                ArrayList<LongHolder> temp2 = new ArrayList<LongHolder>();
                for (int j = 0; j < 6; j++) {
                    LongHolder lh2 = new LongHolder();
                    lh2.setL(newUpdateIndivs.get(i).getPromotionList().get(j).getLongValue());
                    temp2.add(lh2);
                }
                promotions.add(temp2);
            }
        }
        return promotions;
    }

    public void setPromotions(ArrayList<ArrayList<LongHolder>> promotions) {
        this.promotions = promotions;
    }

    public String confirmUpdate() {
        // for debugging
        
        for (int i = 0; i < 4; i++) {
            System.out.println("testing promo:" + newUpdateIndivs.get(i).getPromotionList().toString());
        }
        
        selectedSF = salesForecastSession.getSalesForecastFromIdStr(selectedSF.getSfIdStr());
        for (int i = 0; i < 4; i++) {
            selectedSF.returnProductIndivForecast(i).getUpdateIndivs().add(newUpdateIndivs.get(i));
        }

        //  update sops
        if (salesForecastSession.saveEditedSalesForecast(selectedSF)) {
            FacesContext.getCurrentInstance().getExternalContext().getSessionMap().remove(SalesForecastMgmtManagerBean.UPDATE_SF);
            FacesContext.getCurrentInstance().getExternalContext().getSessionMap().remove(NEW_UPDATE_INDIVS);
            return getRedirectPath(Consts.EDIT_SALES_FORECAST_PATH + "Confirm");
        } else {
            FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage(FacesMessage.SEVERITY_ERROR, "Unsuccessful",
                    "not able to persist into the database"));
            return null;
        }
    }

    public boolean renderProOrHAdj(Integer pos, Integer productIndex) {
        SimpleDateFormat sdf = new SimpleDateFormat("MM");
        int currentMonth = Integer.valueOf(sdf.format(currentTime));
        sdf = new SimpleDateFormat("yyyy");
        int currentYear = Integer.valueOf(sdf.format(currentTime));
        boolean render = false;

        // testing:
//        currentMonth = 11;
//        currentYear = 2011;
//        currentMonth = 1;
//        currentYear = 2012;
//        currentMonth = 5;
//        currentYear = 2012;
//        currentMonth = 10;
//        currentYear = 2011;

        if (selectedSF.getStartPeriodYear().equals(currentYear)) {
            int diff = (pos + 1) - currentMonth;
            if (diff >= 2) {
                render = true;
            }
        } else {
            if (selectedSF.getStartPeriodYear().intValue() == currentYear + 1) {
                if (selectedSF.getStartPeriodMonth().intValue() > 6) {
                    pos += 6;
                }
                pos = pos + 12;
                int diff = (pos + 1) - currentMonth;
                if (diff >= 2) {
                    render = true;
                }
            }
        }
        return render;
    }

    public boolean renderMovingAverage(Integer pos, Integer productIndex) {
        SimpleDateFormat sdf = new SimpleDateFormat("MM");
        int currentMonth = Integer.valueOf(sdf.format(currentTime));
        sdf = new SimpleDateFormat("yyyy");
        int currentYear = Integer.valueOf(sdf.format(currentTime));
        boolean render = false;

        // testing:
//        currentMonth = 11;
//        currentYear = 2011;
//        currentMonth = 1;
//        currentYear = 2012;
//        currentMonth = 5;
//        currentYear = 2012;
//        currentMonth = 10;
//        currentYear = 2011;

        if (selectedSF.getStartPeriodYear().equals(currentYear)) {
            int diff = (pos + 1) - currentMonth;
            if (diff == 2) {
                render = true;
            }
        } else {
            if (selectedSF.getStartPeriodYear().intValue() == currentYear + 1) {
                if (selectedSF.getStartPeriodMonth().intValue() > 6) {
                    pos += 6;
                }
                pos = pos + 12;
                int diff = (pos + 1) - currentMonth;
                if (diff == 2) {
                    render = true;
                }
            }
        }
        return render;
    }

    public void selectProduct(Integer productId) {
        setSelectedProductId(productId);
    }

    public Integer getSelectedProductId() {
        return selectedProductId;
    }

    public void setSelectedProductId(Integer selectedProductId) {
        this.selectedProductId = selectedProductId;
    }

    public ArrayList<LabelNValue> getReferencedActual() {
        return referencedActual;
    }

    public void setReferencedActual(ArrayList<LabelNValue> referencedActual) {
        this.referencedActual = referencedActual;
    }

    public void calculateSelectedMovAvg(ActionEvent event) {
        // isValid
        RequestContext requestContext = RequestContext.getCurrentInstance();
        // check whether the value is more than 0
        if (newUpdateIndivs.get(selectedProductId).getMovingAvgIndexN() <= 0) {
            FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage(FacesMessage.SEVERITY_ERROR, "Unsuccessful for product" + returnProductName(selectedProductId),
                    "Please input valid moving average index. Index should be greater than 0."));
            requestContext.addCallbackParam("isValid", false);
            return;
        }
        // check whether the index is too large and out of bound, if not then return the values
        referencedActual = salesForecastSession.getMovAverage(selectedProductId, currentTime, newUpdateIndivs.get(selectedProductId).getMovingAvgIndexN());
        // update reference table's data
        if (referencedActual == null) {
            FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage(FacesMessage.SEVERITY_ERROR, "Unsuccessful for product" + returnProductName(selectedProductId),
                    "Please input valid moving average index. Index is too large and beyond the start of the production"));
            requestContext.addCallbackParam("isValid", false);
            return;
        }
        // calculate moving average
        Long movAverage = new Long(0);
        for (LabelNValue lnv : referencedActual) {
            movAverage += lnv.getValue();
        }
        movAverage = Math.round(movAverage * 1.0 / referencedActual.size());
        newUpdateIndivs.get(selectedProductId).setMovingAvgResult(movAverage);
        requestContext.addCallbackParam("isValid", true);
    }

    public void calculateFinal(Integer selectedProductId) {
        // validation 1: to check whether promotion has negative values
        for (int i = 0; i < 6; i++) {
            if (promotions.get(selectedProductId).get(i).getL() < 0) {
                FacesContext.getCurrentInstance().addMessage(null,
                        new FacesMessage(FacesMessage.SEVERITY_ERROR, "Unsuccessful for product " + returnProductName(selectedProductId),
                        "You promotion cannot be negative"));
                return;
            }
        }
        // calculate and update final values
        UpdateIndiv indiv = newUpdateIndivs.get(selectedProductId);
        for (int i = 0; i < 6; i++) {
            indiv.getHumanAdjustList().get(i).setLongValue(humanAdjusts.get(selectedProductId).get(i).getL());
            indiv.getPromotionList().get(i).setLongValue(promotions.get(selectedProductId).get(i).getL());
            Long value = humanAdjusts.get(selectedProductId).get(i).getL() + promotions.get(selectedProductId).get(i).getL()
                    + selectedSF.returnProductIndivForecast(selectedProductId).getBaseProjectionSelected().get(i).getLongValue();
            indiv.getFinalValues().get(i).setLongValue(value);
        }
    }

    public void calculateAll(ActionEvent event) {
        // check whether promotion bigger than 0
        for (int j = 0; j < 4; j++) {
            for (int i = 0; i < 6; i++) {
                if (promotions.get(j).get(i).getL() < 0) {
                    FacesContext.getCurrentInstance().addMessage(null,
                            new FacesMessage(FacesMessage.SEVERITY_ERROR, "Unsuccessful for product " + returnProductName(j),
                            "You promotion cannot be negative"));
                    return;
                }
            }
        }
        // calculate all values
        for (int j = 0; j < 4; j++) {
            UpdateIndiv indiv = newUpdateIndivs.get(j);
            for (int i = 0; i < 6; i++) {
                indiv.getHumanAdjustList().get(i).setLongValue(humanAdjusts.get(j).get(i).getL());
                indiv.getPromotionList().get(i).setLongValue(promotions.get(j).get(i).getL());
                Long value = humanAdjusts.get(j).get(i).getL() + promotions.get(j).get(i).getL()
                        + selectedSF.returnProductIndivForecast(j).getBaseProjectionSelected().get(i).getLongValue();
                indiv.getFinalValues().get(i).setLongValue(value);;
            }
        }
    }
}
